
// 块级作用域，从babel编译的代码中可以发现名字被加了下划线作为前缀，可以理解为一种语法糖吧。
{
  let a = 10;
  var b = 1;
  console.log(a); //10
  console.log(b); //1
}
console.log(a); // undefined
console.log(b); // 1


// 循环计数器，从babel编译好的代码可以发现是利用函数闭包来实现的
// 好处在于所设置的变量只在for的块作用域内有效，可以避免大量变量重复的问题
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

// ES6规定暂时性死区和不存在变量提升，主要是为了减少运行时错误，防止在变量声明前就使用这个变量，从而导致意料之外的行为。
// 这样的错误在ES5是很常见的，现在有了这种规定，避免此类错误就很容易了。
function do_something(){
	console.log(a); // ReferenceError
	let a = 1;
}
do_something();


// 暂时性死区。在代码块内，使用let命令声明变量之前，该变量都是不可用的。
if (true) {
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp;
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

// 函数的作用域是其声明时所在的作用域。
let foo1 = 'outer';

function bar1(func = x => foo1) {
  let foo1 = 'inner';
  console.log(func()); // outer
}

bar1();

//与上面相同效果
let foo2 = 'outer';
let f = x => foo2;

function bar2(func = f) {
  let foo2 = 'inner';
  console.log(func()); // outer
}

bar2();


// 不允许重复声明
// 报错
function func1() {
  let a = 10;
  //var a = 1;
}

// 报错
function func2() {
  let a = 10;
  //let a = 1;
}

// 报错
function func3(arg) {
  //let arg; 
}

// 不报错
function func4(arg) {
  {
    let arg; 
  }
}

// 总结下来let主要有以下几个特点：1.块级作用域 2.没有变量提升（存在暂时性死区） 3.不能重复声明
// 目的是：限制了变量的作用范围，避免大量程序因作用域而造成的错误